# -*- coding:utf-8 -*-
# @FileName  :ADBHelper.py
# @Time      :2022/6/13 15:59
# @Author    :Rengar
# """adb基类"""

import os
import platform
import re
import subprocess
import sys
from time import sleep

from six import string_types, text_type

from amat_app.core.utils import get_standard_encoding, Log


class ADBHelper:

    def __init__(self, dev_name=None):
        """
        :param dev_name: 如果不传设备名称,则为usb设备
        """
        self.__system = platform.system()
        self.__find = ''
        self.__get_find()
        self.__command = []
        self.__check_adb()
        self.dev_name = dev_name

        # if self.dev_name != '?' and ":" not in self.dev_name:
        #     self.dev_name += ":5555"

        self.__init_connect()
        self.__pid = None

        # self.unlock_adb_shell()  # 先解锁shell，否则很多命令不方便使用

    def __init_connect(self):
        _dev_state = self.connect()
        if _dev_state[1]:
            return True
        else:
            raise

    def unlock_adb_shell(self):
        """从V2.0.1.6版本开始，需要密码才能进入adb shell，这里进行解锁，不需要密码"""

        try:
            self.cmd("root")
            self.cmd("remount")
            with open("adb.cfg", "w") as f:
                f.write(f'0:sybersense*xp02')
            self.cmd('push adb.cfg /data/local/tmp')
            os.remove('adb.cfg')

            return 0
        except Exception as e:

            return -1
        # _result, _err = self.shell(_unlock_cmd

    def lock_adb_shell(self, pwd="sybersense*xp02"):
        """上锁，使Panel需要输入密码才能进行shell命令"""

        try:
            self.cmd("root")
            self.cmd("remount")
            with open("adb.cfg", "w") as f:
                f.write(f'1:{pwd}')
            self.cmd('push adb.cfg /data/local/tmp')
            os.remove('adb.cfg')

            return 0
        except Exception as e:
            Log.error(f"panel shell 命令加锁失败：{e}")
            return -1

    # 2022/12/12 11:31 todo adb -t 解决多个USB设备同时连接

    def __get_find(self):
        """
        判断系统类型，windows使用findstr，linux使用grep
        :return:
        """
        if self.__system == "Windows":
            self.__find = "findstr"
        else:
            self.__find = "grep"

    def __check_adb(self):
        """
        检查环境中是否有adb
        :return:
        """
        if "ANDROID_HOME" in os.environ:
            adb_path = os.path.join(os.environ["ANDROID_HOME"], "platform-tools", "adb.exe")
            if os.path.exists(adb_path):
                self.__command += [adb_path]
            else:
                raise EnvironmentError('ADB  不存在')
        else:
            raise EnvironmentError("ANDROID_HOME 不存在")

    def _set_command_opts(self, server_addr=None):
        """
        组合command参数
        :return:
        """
        self.host = server_addr[0] if server_addr else "127.0.0.1"
        self.port = server_addr[1] if server_addr else 5037
        if self.host not in ("localhost", "127.0.0.1"):
            self.__command += ['-H', self.host]
        if self.port != 5037:
            self.__command += ["-P", str(self.port)]

    @staticmethod
    def __split_cmd(cmds):
        """
        拆分命令
        :return:
        """
        if isinstance(cmds, string_types):
            return cmds.split()
        else:
            return list(cmds)

    def start_cmd(self, commands, device=True, text=False):
        """
        启动一个cmd进程
        :param commands: 命令参数
        :param device: 是否加 -s
        :param text:
        :return:
        """
        if device:
            # 没有设备，默认为USB设备
            if not self.dev_name:
                cmd_opt = self.__command + ['-d']
            else:
                cmd_opt = self.__command + ["-s", self.dev_name]
        else:
            cmd_opt = self.__command

        cmds = cmd_opt + self.__split_cmd(commands)

        # creationflags=subprocess.CREATE_NO_WINDOW 隐藏命令框
        process = subprocess.Popen(cmds, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                   creationflags=subprocess.CREATE_NO_WINDOW, text=text)  # in Python 3.7+

        self.__pid = process.pid
        return process

    def cmd(self, commands, device=True, ensure_unicode=True, timeout=None):
        """

        :param commands:
        :param device:
        :param ensure_unicode: 标准编码
        :param timeout:
        :return:
        """
        for i in range(2):
            process = self.start_cmd(commands, device)
            # 是否设置超时时间
            if timeout:
                stdout, stderr = process.communicate(timeout=timeout)
            else:
                stdout, stderr = process.communicate()
            # 确保编码正确
            if ensure_unicode:
                stdout = stdout.decode(get_standard_encoding(sys.stdout), errors='ignore')
                stderr = stderr.decode(get_standard_encoding(sys.stderr), errors='ignore')
            # if process.returncode > 0:
            #     pattern = (r"error:\s*((device \'\S+\' not found)|(cannot connect to daemon at [\w\:\s\.]+ "
            #                r"Connection timed out)) ")
            #     if isinstance(stderr, binary_type):
            #         pattern = pattern.encode("utf-8")
            # if not isinstance(stderr, str):
            #     stderr = stderr.decode(encoding="utf-8", errors='ignore')
            # if re.search(pattern, stderr):
            #     Log.warning(pattern)
            # return None, None
            # else:
            #     Log.warning(f"stdout: {stdout}, stderr: {stderr}")
            # return None, None
            try:
                if "Wrong 'passwd *****'" in str(stderr):
                    self.unlock_adb_shell()
                    continue
            except Exception as e:
                Log.error(e)
            return stdout, stderr

    def start_server(self):
        """
        启动adb 服务
        :return:
        """
        return self.cmd("start-server", device=False)[0]

    def kill_server(self):
        """
        kill ADB 服务
        :return:
        """
        return self.cmd("kill-server", device=False)[0]

    def version(self):
        """
        执行 adb version 获取adb版本信息
        :return:
        """
        return self.cmd("version", device=False)[0].strip()

    @staticmethod
    def close_process(process):
        """
        关闭进程
        :param process:
        :return:
        """

        def close_pipe(pipe):
            if pipe:
                pipe.close()

        close_pipe(process.stdin)
        close_pipe(process.stdout)
        close_pipe(process.stderr)

    def devices(self, state=None):
        """
        获取状态为state的设备
        :param state:
        :return:
        """
        patten = re.compile(r'^[\w\d.:-]+\t\w+$')
        devs_list = []
        result = self.cmd("devices", device=False)[0]
        for item in result.splitlines():
            item = item.strip()
            if not item or not patten.match(item) and "?" not in item:
                continue
            ser, _state = item.split("\t")
            if state and _state != state:
                continue
            devs_list.append((ser, _state))
        return devs_list
        # _result = self.cmd("devices", device=False)
        # return result

    def get_devices(self):
        """
        获取状态为device的设备
        :return:
        """

        result = self.devices(state='device')
        _dev_list = []
        for item in result:
            if not item and not isinstance(item, tuple):
                continue
            _dev_list.append(item[0])
        # Log.debug(f'获取状态为device的设备：{_dev_list}')
        return _dev_list

    def get_status(self):
        """
        获取设备状态
        :return:
        """
        process = self.start_cmd("get-state")
        stdout, stderr = process.communicate()
        stdout = stdout.decode(get_standard_encoding(sys.stdout))
        stderr = stderr.decode(get_standard_encoding(sys.stderr))
        if process.returncode == 0:
            return stdout.strip(), stderr
        elif "not found" in stderr:
            return None, stderr
        elif "device offline" in stderr:
            return "offline", stderr
        else:
            return None, stderr

    def connect(self) -> tuple:
        """
        :return: 一个元组， 包含是否连接成功，以及信息
        """

        if self.dev_name != '?' and self.dev_name is not None:
            if self.get_status()[0] == "offline":  # 判断是否已存在
                self.disconnect()
                sleep(1)
            result = self.cmd(f"connect {self.dev_name}")[0]
            if "cannot" in result:
                return False, result
            else:
                return True, result
        else:
            return self.is_usb_connected(), 'usb device'

    def disconnect(self):
        """
        断开连接
        :return:
        """

        result = self.cmd(f"disconnect {self.dev_name}")[0]
        return result

    def wait_for_device(self, timeout=5):
        """
        等待设备连接
        :param timeout:
        :return:
        """
        try:
            self.cmd("wait-for-device", timeout=timeout)
            return True
        except RuntimeError as e:
            Log.debug(f'wait device timeout')
            return False
        except Exception as e:
            Log.debug(f'adb wait for device error: {e}')
            return None

    def start_shell(self, commands):
        """
        执行adb shell 命令
        :return:
        """
        cmds = ["shell"] + self.__split_cmd(commands)
        return self.start_cmd(cmds)

    def native_shell(self, commands, ensure_unicode=True, timeout=None):
        """
        原生的adb shell ,不更改编码
        :return:
        """
        cmds = ["shell"] + self.__split_cmd(commands)
        result, __error = self.cmd(cmds, ensure_unicode=False, timeout=timeout)
        if not ensure_unicode:
            return result, __error
        try:
            if not result:
                _var_result = ''
            else:
                _var_result = result.decode("utf-8")
            if not __error:
                _var_error = ""
            else:
                _var_error = __error.decode("utf-8")
            return _var_result, _var_error
        except UnicodeDecodeError:
            Log.warning(f"adb shell output decode utf-8 失败, repr={repr(result)}")
            return text_type(repr(result))

    def shell(self, command, timeout=None):
        """

        :param timeout: 超时时间
        :param command:
        :return:
        """

        result, __error = '', ''
        for i in range(3):
            try:
                result, __error = self.native_shell(command, timeout=timeout)
                # 处理连接成功但是shell提示 close的情况
                __err_str = "error: closed"
                # print(f'调试信息：{__error}')
                if "Wrong 'passwd *****'" in str(__error):
                    self.unlock_adb_shell()
                    continue
                if __err_str in result or __err_str in __error:
                    self.re_connect()
                    continue
                else:
                    break
            except Exception as e:
                Log.warning(f'执行adb shell命令出错：{e}')
                continue
        else:
            Log.error(f'adb shell {command} 执行失败')
        return result, __error

    def re_connect(self):
        """
        重新连接
        :return:
        """
        self.disconnect()
        self.connect()

    def get_device_ip_address(self):
        """
        获取 panel ip 地址
        :return: 如果有ip则返回ip，没有ip则返回None
        """

        def _get_ip_address_from_interface(interface):
            """Get device ip from target network interface."""
            # android >= 6.0: ip -f inet addr show {interface}
            try:
                res, __error = self.shell('ip -f inet addr show {}'.format(interface))
            except Exception as e:
                # Log.warning(f"shell ip -f inet addr show {interface} error: {e}")
                res = ''
            matcher = re.search(r"inet (\d+\.){3}\d+", res)
            if matcher:
                return matcher.group().split(" ")[-1]

            # android >= 6.0 backup method: ifconfig
            try:
                res, __error = self.shell('ifconfig')
            except Exception as e:
                # Log.warning(f"shell ifconfig error: {e}")
                res = ''
            matcher = re.search(interface + r'.*?inet addr:((\d+\.){3}\d+)', res, re.DOTALL)
            if matcher:
                return matcher.group(1)

            # android <= 6.0: netcfg
            try:
                res, __error = self.shell('netcfg')
            except Exception as e:
                # Log.warning(f"netcfg error: {e}")
                res = ''
            matcher = re.search(interface + r'.* ((\d+\.){3}\d+)/\d+', res)
            if matcher:
                return matcher.group(1)

            # android <= 6.0 backup method: getprop dhcp.{}.ipaddress
            try:
                res, __error = self.shell('getprop dhcp.{}.ipaddress'.format(interface))
            except Exception as e:
                # Log.warning(f"getprop dhcp.{interface}.ipaddress error: {e}")
                res = ''
            IP_PATTERN = re.compile(r'(\d+\.){3}\d+')
            matcher = IP_PATTERN.search(res)
            if matcher:
                return matcher.group(0)

            # sorry, no more methods...
            return None

        # Log.info('获取panel 的ip地址')
        _out, _err = self.shell('ifconfig -a wlan0')
        _matcher = re.search("wlan0" + r'.*?inet addr:((\d+\.){3}\d+)', _out, re.DOTALL)
        if _matcher:
            return _matcher.group(1)

        interfaces = ('eth0', 'eth1')
        for i in interfaces:
            ip = _get_ip_address_from_interface(i)
            if ip and not ip.startswith('127.') and not ip.startswith('169.'):
                return ip
        return None

    def uninstall(self, package):
        """
        卸载程序
        :param package:
        :return:
        """
        return self.cmd(['uninstall', package])[0]

    def install_app(self, filepath, replace=False, install_options=None) -> tuple:
        """

        :param filepath: 安装包所在路径
        :param replace: 强制安装
        :param install_options: 安装时的额外参数 -r 替换已存在的应用程序，也就是说强制安装
                                             -l 锁定该应用程序
                                             -t 允许测试包
                                             -s 把应用程序安装到sd卡上
                                             -d 允许进行将见状，也就是安装的比手机上带的版本低
                                             -g 为应用程序授予所有运行时的权限

        :return: 返回一个元组，结果(bool)和内容(str)
        """
        if self.dev_name is None:

            Log.debug(f'USB设备 安装程序{filepath}')
        else:
            Log.debug(f'设备{self.dev_name} 安装程序{filepath}')
        if not os.path.isfile(filepath):
            return False, ("file: %s does not exists" % (repr(filepath)))

        if not install_options or type(install_options) != list:
            install_options = []
        if replace:
            install_options.append("-r")
        cmds = ["install", ] + install_options + [filepath, ]
        result = self.cmd(cmds)
        print(result)
        out = result[0]
        if out is None:
            return False, 'Unknown Error'
        if re.search(r"Failure \[.*?]", out):
            return False, f"Installation Failure {repr(out)}"

        return True, out

    def start_application(self, package, activity):
        """
        启动应用
        :param package: 应用包名
        :param activity: 启动activity
        :return:
        """
        # 2023/2/10 10:57 todo 处理activity以包名或.开头
        # 准备借助monkey启动无activity的应用, Monkey是否会影响appium，暂时不使用
        # if not activity:
        #     self.shell(['monkey', '-p', package, '-c', 'android.intent.category.LAUNCHER', '1'])
        # else:
        __result, __error = self.shell(['am', 'start', '-n', '%s/%s.%s' % (package, package, activity)])
        return __result, __error

    def get_device_imei(self, transform=True):
        """
        获取设备IMEI,
        :param transform: 是否转换为16进制，且只取最后12位
        :return:
        """
        # Log.debug(f'开始获取设备{self.dev_name}的IMEI')
        result, __error = self.shell('service call iphonesubinfo 1')
        # print(result)
        # print(re.findall(re.compile("'.+?'"), result))
        # imei = ''
        # for i in re.findall(re.compile("'.+?'"), result):
        #     imei += i.replace('.', '').replace("'", '').replace(' ', '')
        imei = self.__format_iphone_sub_info(result)
        if imei:
            if transform:
                # Log.debug(f'获取设备{self.dev_name}的IMEI：{hex(int(imei))[-12:].upper()}')
                return hex(int(imei))[-12:].upper()
            else:
                # Log.debug(f'获取设备{self.dev_name}的IMEI：{imei.upper()}')
                return imei.upper()
        else:
            Log.debug(f'未获取到{self.dev_name}的imei')
            return None

    def clear_appium(self):
        """
        清除appium相关应用
        :return:
        """
        Log.debug('清理Appium相关的应用')
        self.uninstall('io.appium.settings')
        sleep(1)
        self.uninstall('io.appium.uiautomator2.server')
        sleep(1)
        self.uninstall('io.appium.uiautomator2.server.test')

    def is_usb_connected(self):
        """
        判断usb是否连接
        :return:
        """
        connected_dev = self.get_status()
        return connected_dev == 'device'

    def get_wifi_state(self):
        """
        获取WiFi连接状态
        :return:
        """
        var = self.get_device_ip_address()
        if var:
            return True
        else:
            return False

    def usb_device_connect_by_wifi(self) -> tuple:
        """
        获取USB设备wifi，并尝试连接
        """
        try:
            _var_ip = self.get_device_ip_address()
            if not _var_ip:
                return False, '未获取到Panel IP'
            _can_connect = ADBHelper(_var_ip).connect()
            Log.debug(f'USB 设备直接连接:{_can_connect}')
            return _can_connect
        except Exception as e:
            Log.error(f'{e}')
            return None, None

    def set_panel_wifi(self, ssid, psw) -> bool:
        """
        设置Panel的wifi
        :param ssid: 需要连接的WIFI ssid
        :param psw: 需要连接的wifi password
        :return:
        """

        def _wpa_set_wifi(_ssid, _psw):
            Log.debug(f'设置Panel的wifi, ssid:{ssid}, psw:qfqfqaf {psw} adfFf')
            # 先root
            self.cmd("root")
            sleep(1)
            self.cmd("remount")
            sleep(1)
            # 打开wifi
            _open_wifi, __error = self.shell('svc wifi enable')
            # Log.debug(f'打开wifi:{_open_wifi}')
            sleep(3)
            # 扫描wifi列表
            _scan_wifi, __error = self.shell('wpa_cli -i wlan0 scan')
            Log.debug(f'scan wifi :{_scan_wifi}')
            sleep(1)
            # 获取wpa_cli wifi列表
            __list_wifi, __error = self.shell('wpa_cli -i wlan0 list_network')
            Log.debug(f'获取wpa_cli wifi列表:{__list_wifi}')
            # 3.判断__list_wifi中是否有ssid为空的列，如果有， 获取id,如果没有，添加一条
            __result = None
            for _item in __list_wifi.split('\n'):
                _item_var = _item.split('any')[0].split()
                _len_item_var = len(_item_var)
                if _len_item_var > 1:
                    for j in range(_len_item_var):
                        if _item_var[j] == _ssid:
                            __result = _item_var[0]
                            break
                    if __result == _item_var[0]:
                        break

                elif _len_item_var == 1:
                    __result = _item_var[0]
                    break
            else:
                __result, __error = self.shell('wpa_cli -i wlan0 add_network')
            Log.debug(f'wpa_cli中空的列:{__result}')
            # 4.设置ssid
            Log.debug(f'执行： {self.__command} -d shell')

            _set_net_cmd = f'wpa_cli -i wlan0 set_network {__result} ssid \'\"{_ssid}\"\';'
            pw, __error = self.shell(_set_net_cmd)
            Log.debug(f'执行： {_set_net_cmd} , result: {pw}')

            # 5.设置psk
            if _psw:
                _set_psk_cmd = f'wpa_cli -i wlan0 set_network {__result} psk \'\"{_psw}\"\''
                pw2, __error = self.shell(_set_psk_cmd)
                Log.debug(f'执行{_set_psk_cmd} result:{pw2}')
            self.shell(f"wpa_cli -i wlan0 enable_network {__result}")
            sleep(1)
            self.shell(f'wpa_cli -i wlan0 select_network {__result}')
            sleep(2)
            # print("设置后wifi： ", self.get_device_ip_address())
            self.shell(f"wpa_cli -i wlan0 save_config")

        Log.info(f'设置Panel的wifi, ssid:{ssid}')
        for i in range(3):
            # 打开wifi
            _enable_wifi, __error = self.shell('svc wifi enable')
            # 打开之后再获取wifi地址
            _var_ip = self.get_device_ip_address()
            # 如果获取到了ip,尝试连接
            if _var_ip:
                ADBHelper().cmd('tcpip 5555')
                _var_connect = ADBHelper(dev_name=_var_ip).connect()
                if _var_connect[0]:
                    Log.info(f'{_var_ip}连接成功')
                    return True
                # 如果连接不成功，尝试设置wifi
                else:
                    Log.debug("连接不成功,准备设置wifi")
                    _wpa_set_wifi(ssid, psw)
            else:
                Log.debug('wifi未连接, 准备设置wifi')
                # 设置wifi
                _wpa_set_wifi(ssid, psw)
        return False

    def reinstall_xp02(self, apk_path):
        """
        卸载旧版本xp02应用，重新新版本
        :return:
        """
        try:
            self.uninstall('com.sybersense.xp02')
            self.uninstall('com.amu.analogsignal')  # 同时卸载模拟信号的应用
            sleep(1)
            __state = self.install_app(f'{apk_path}')
            sleep(1)
            print(__state)
            __new_version = self.app_activity_invalid('ui.HomeDisplayActivity')
            if __new_version:
                __start = self.start_new_xp02()
            else:
                __start = self.start_application(package='com.sybersense.xp02', activity='DisPlayActivity')
            print(f"启动应用:{__start}")
            return 0
        except Exception as e:
            print(e)
            return -1

    def install_new_xp02(self, apk_path):
        """
        卸载旧版本xp02应用，重新安装新版本,不启动
        :return:
        """
        try:
            self.uninstall('com.sybersense.xp02')
            self.uninstall('com.amu.analogsignal')  # 同时卸载模拟信号的应用
            sleep(1)
            __state = self.install_app(f'{apk_path}')
            sleep(1)
            print(__state)
            return 0
        except Exception as e:
            print(e)
            return -1

    def check_app(self, package, timeout=10):
        """
        Perform `adb shell dumpsys package` command and check if package exists on the device

        Args:
            package: package name
            timeout:
        Raises:
            AirtestError: if package is not found

        Returns:
            True if package has been found


        """
        for i in range(2):
            output, __error = self.shell(['dumpsys', 'package', package])
            # print(f' output: {output}, __error:{__error}')
            if "device offline" in __error:
                Log.debug(f'device offline')
                return None
            if f"device '{self.dev_name}' not found" in __error:
                # Panel未启动
                Log.debug(f'未检测到设备, 等待{int(timeout / 2)}s 重试')
                self.wait_for_device(timeout=int(timeout / 2))
                continue
            pattern = r'Package\s+\[' + str(package) + '\]'
            match = re.search(pattern, output)
            if match is None:
                return False
            return True
        else:
            # 超时未找到设备,返回None
            Log.debug(f'adb wait device timeout: {timeout}')
            return None

    def __get_process(self, package_name):
        """
        获取进程信息
        :param package_name:
        :return:
        """

        pid_command = self.shell("ps | %s %s$" % ("grep", package_name))
        # self.Log.info(f'获取{package_name}进程信息: {pid_command}')
        return pid_command

    def get_pid(self, package_name):
        """
        获取pid
        :return:
        """
        pid_command = self.__get_process(package_name)
        if pid_command == '':
            # print("The process does not exist.")
            Log.warning(f'{package_name}的进程不存在')
            return pid_command

        req = re.compile(r"\d+")
        result = str(pid_command).split()
        result.remove(result[0])
        # self.Log.info(f'获取{package_name}的进程：{req.findall(" ".join(result))[0]}')
        return req.findall(" ".join(result))[0]

    def process_exists(self, package_name):
        """
        返回进程是否存在
        :param package_name:
        :return:
        """
        process, __error = self.__get_process(package_name)
        if not process:
            Log.debug(f"{__error}")
            return False
        return package_name in process

    def check_xp02(self):
        """
        检查xp02应用是否安装
        :return:
        """
        _result = self.check_app('com.sybersense.xp02')
        if _result:
            Log.debug(f'{self.dev_name}已经安装了xp02应用')
            return True
        else:
            Log.debug(f'{self.dev_name}没有安装xp02应用')
            return False

    def get_storage(self):
        # 存储
        res, __error = self.shell("df /data")
        pat = re.compile(r".*/data\s+(\S+)", re.DOTALL)
        if pat.match(res):
            _str = pat.match(res).group(1)
        else:
            pat = re.compile(r".*\s+(\S+)\s+\S+\s+\S+\s+\S+\s+/data", re.DOTALL)
            _str = pat.match(res).group(1)
        if 'G' in _str:
            _num = round(float(_str[:-1]))
        elif 'M' in _str:
            _num = round(float(_str[:-1]) / 1000.0)
        else:
            _num = round(float(_str) / 1000.0 / 1000.0)
        if _num > 64:
            res = '128G'
        elif _num > 32:
            res = '64G'
        elif _num > 16:
            res = '32G'
        elif _num > 8:
            res = '16G'
        else:
            res = '8G'
        return res

    def check_sim_card(self):
        """
        检查设备SIM卡
        :return:
        """
        _result, __error = self.shell('getprop | %s gsm.operator.alpha' % self.__find)
        # print(_result)
        # return len(self.shell('getprop | %s gsm.operator.alpha]' % self.__find).read().strip().split()[-1]) > 2

    def get_device_operators(self):
        """
        获取运营商
        :return:
        """
        result, __error = self.shell('getprop | %s gsm.operator.alpha]' % self.__find)
        return result

    def start_new_xp02(self):
        """
        启动新框架的XP02应用
        :return:
        """
        __result, __error = self.start_application("com.sybersense.xp02", "ui.HomeDisplayActivity")
        sleep(5)
        print(f'启动新框架应用：{__result,}, error:{__error}')
        return __result, __error

    def app_activity_invalid(self, activity):
        """
        判断XP02应用启动包名是否一致
        :return:
        """
        if activity is None:
            return None
        if not isinstance(activity, str):
            try:
                activity = str(activity)
            except Exception as e:
                Log.debug(e)
                return None
        __result, err = self.shell(f"dumpsys package com.sybersense.xp02")

        if activity in __result:
            Log.debug(f'应用启动Active为:{activity}')
            return True
        else:
            Log.debug(f'应用启动Activity不符：预期为：{activity}')
            return False
        # if ".DisPlayActivity" in __result:
        #     Log.debug(f'Is New Framework:False')
        #     return False
        # elif ".ui.HomeDisplayActivity" in __result:
        #     Log.debug(f'Is New Framework:True')
        #     return True
        # else:
        #     Log.debug(f'Is New Framework:None, dumpsys package:{__result}, error:{err}')
        #     return None
        # elif
        # return __result

    def get_date(self, hour_sys_12: bool = True, format_str=True):
        """
        获取Panel的时间
        :param format_str: 是否格式化(按照Panel历史记录上显示的格式)
        :param hour_sys_12: 是否为12小时制
        :return:
        """
        try:
            _cmd = ["date"]
            if format_str:

                if hour_sys_12:
                    _cmd += ["-D", "FORMAT", "+'%m/%d/%Y\n%H:%M %p'"]
                else:
                    _cmd += ["-D", "FORMAT", "+'%m/%d/%Y\n%H:%M'"]  # %p:AM/PM
            # print(_cmd)
            _date_str, _err = self.shell(_cmd)
            if _err is not None and _err != '':
                Log.debug(f'获取时间时出错：{_err}')
            try:
                _date_str.strip()
            except Exception as e:
                print(e)
        except Exception as e:
            print(e)
            return ''
        return _date_str

    # 获取传入包名的版本号(全版本号)
    def get_package_version_name(self, package="com.sybersense.xp02"):
        """
        获取传入包名的版本号(全版本号)
        :param package:
        :return: e.g. 2.3.2.1609.06
        """
        _err = None
        try:
            _get_version_cmd = f'shell pm dump {package} | grep "versionName"'
            _stdout, _stderr = self.cmd(_get_version_cmd)
            _err = _stderr
            _package_version_name = _stdout.strip().split("=")[1]
            Log.debug(f"{package} version name = {_package_version_name}")
            return _package_version_name
        except Exception as e:
            Log.error(f"获取应用版本是出错：{e}，{_err}")
            return None

    def get_app_info(self, package, filter_key=None):
        _err = ''
        try:
            if filter_key is None:
                _cmd = f'shell pm dump {package}'
            else:
                _cmd = f'shell pm dump {package} | grep "{filter_key}"'
            _stdout, _stderr = self.cmd(_cmd)
            _err = _stderr
            return _stdout
            # _package_version_name = _stdout.strip().split("=")[1]
            # Log.debug(f"{package} version name = {_package_version_name}")
            # return _package_version_name
        except Exception as e:
            Log.error(f"获取应用版本是出错：{e}，{_err}")
            return None

    # 获取传入包名的版本号(大版本)
    def get_package_version_code(self, package="com.sybersense.xp02"):
        """
        获取传入包名的版本号(大版本)
        :param package:
        :return: e.g. 1609
        """
        _get_version_cmd = f'shell pm dump {package} | grep "versionCode"'
        _stdout, _stderr = self.cmd(_get_version_cmd)

        if _stdout:
            try:
                _package_version_code = _stdout.split()[0].split("=")[1]
                Log.debug(f"{package} version code = {_package_version_code}")
                return _package_version_code
            except Exception as e:
                Log.debug(e)
                return None
        else:
            Log.debug(_stderr)
            return None

    def get_current_activity(self):
        """获取当前顶层Activity"""
        try:
            _cmd = "shell dumpsys window | grep mCurrentFocus"
            _out, _err = self.cmd(_cmd)
            return _out
        except Exception as e:
            Log.error(f"{e}")
            return None

    def get_system_version(self, xp02_format=True):
        """
        获取System Version
        xp02_format:转换为XP02显示的格式(eg:2.0.1.4)
        :return: str
        """
        try:
            _stdout, _stderr = self.shell("getprop ro.build.display.id")
        except Exception as e:
            Log.warning(f'获取系统版本出错：{e}')
            return None
        if not isinstance(_stdout, str) or _stdout.strip() == '':
            Log.warning(f'未找到系统版本：{_stderr}')
            return None
        if not xp02_format:
            return _stdout
        _result = None
        try:
            _pattern = r'-V(.*?)-'
            _result = re.findall(_pattern, _stdout)[0]
        except Exception as e:
            Log.warning(e)
        return _result

    def get_sim1_iccid(self):

        _cmd = "service call iphonesubinfo 11"

        _result, _err = self.shell(_cmd)
        _iccid = self.__format_iphone_sub_info(_result)
        return _iccid

    @staticmethod
    def __format_iphone_sub_info(info_str):
        """
        提取iphonesubinfo的结果
        :param info_str: 需要提取的字符串
        :return:
        """
        try:
            _result = ''
            for i in re.findall(re.compile("'.+?'"), info_str):
                _result += i.replace('.', '').replace("'", '').replace(' ', '')
        except Exception as e:
            Log.error(f"提取iphone sub info出错：{e}")
            return None
        return _result

    # 获取Panel系统日期和时间
    def get_panel_system_date(self, udid, format_str: str = "%m/%d/%Y %H:%M:%S %u"):
        """
        获取Panel系统日期和时间
        :param udid:
        :param format_str: 输出格式，常用参数 - %Y 年, %m 月, %d 日, %H 时, %M 分, %S 秒, %u 星期 (1-7, 1=星期一),
        其他请使用adb命令 'adb shell date --help' 查看
        :return: e.g. Thu Sep 28 05:22:29 GMT 2023
        """
        _get_time_cmd = f"-s {udid} shell date"
        if format_str:
            _get_time_cmd += f" +'{format_str}'"
        _stdout, _stderr = self.cmd(_get_time_cmd)

        if _stdout:
            try:
                _time_str = _stdout.strip()
                Log.debug(f"The Panel system time obtained by Adb is '{_time_str}'")
                return _time_str
            except Exception as e:
                Log.debug(e)
                return None
        else:
            Log.debug(_stderr)
            return None






if __name__ == '__main__':
    ...
    # _ce = my_func(udid="192.168.1.133:5555")
    # print(f"_ce： {_ce}")
    # ad = ADBHelper(dev_name="192.168.1.133:5555")
    # _sta = ad.get_status()
    # if _sta[0].lower() == 'offline':
    #     ad.disconnect()
    #     _con = ad.connect()
    #     print(_con)
